/**
 * File: AbstractIter.java
 * Created by: mhaimel
 * Created on: 18 Aug 2009
 * CVS:  $Id: AbstractIter.java,v 1.1 2009/08/27 14:52:44 mhaimel Exp $
 */
package uk.ac.ebi.curtain.util.io;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.regex.Pattern;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.NotImplementedException;
import org.apache.commons.lang.StringUtils;

import uk.ac.ebi.curtain.utils.CurtainUncheckedException;
import uk.ac.ebi.curtain.utils.io.impl.FileIO;

/**
 * @author mhaimel
 *
 */
public abstract class AbstractIter <T> implements Iterator<T>, Closeable {
	
	private File inFile;
	private T next = null;
	private BufferedReader in = null;
	
	public AbstractIter(File f) {
		this(f,null);
	}
	public AbstractIter(File f,BufferedReader in) {
		this.inFile = f;
		this.in = in;
	}

	public boolean hasNext() {
		T n = _getNext();
		next = n;
		return null != n;
	}
	
	private T _getNext(){
		String line = _nextLine();
		if(line == null){
			return null;
		} else {
			return _buildEntry(line);
		}
	}
	
	
	private Pattern split_pattern = Pattern.compile("\\t");
	
	protected T _buildEntry(String line) {
		String[] arr = split_pattern.split(line);
		return _buildEntry(arr);
	}
	
	protected abstract T _buildEntry(String[] arr);

	private String _nextLine() {
		if(null == in){
			try {
				in = new FileIO(inFile).getBufferedReader();
			} catch (IOException e) {
				throw new CurtainUncheckedException("Problems opening file " + inFile,e);
			}
		} 
		String line = null;

		try {
			// skip empty / blank lines
			while((line = in.readLine()) != null && StringUtils.isBlank(line)){
				/* Do nothing with empty lines */
			}
			if(line == null){
				close();
			}
		} catch (IOException e) {
			throw new CurtainUncheckedException("Problems reading from file " + inFile,e);
		}
		return line;
	}
	
	public void close() throws IOException {
		IOUtils.closeQuietly(in);
		in = null;
	}

	public T next() {
		return next;
	}

	public void remove() {
		throw new NotImplementedException("Not supported!");
	}
	
}
